#ifndef __COTASIA_SMART_POINTER_H__
#define __COTASIA_SMART_POINTER_H__

#include <pthread.h>

#include "common.h"


template <typename T> class cotasia::SmartPointer
{
public:
    static SmartPointer<T> null_pointer;

public:
    SmartPointer<T>(Object *obj = NULL)
        : __obj__(NULL), __count_mutex__(NULL)
    {
        if (NULL == obj) {
            return;
        }

        cotasia::InheritanceShip<Object, T> inh;
        if (! inh) {
            ASSERT(0);
        }
        __obj__ = reinterpret_cast<T *>(obj);

        this->__count_mutex__ = __obj__->__count_mutex__;

        ASSERT(0 == ::pthread_mutex_lock(this->__count_mutex__));
        __obj__->__ref_increase__();
        ASSERT(0 == ::pthread_mutex_unlock(this->__count_mutex__));

        return;
    }

    // stl某些容器要求拷贝构造函数不能使用explicit
    SmartPointer<T>(SmartPointer<T> const &other)
        : __obj__(NULL), __count_mutex__(NULL)
    {
        *this = other;
    }

    SmartPointer<T> const &operator =(SmartPointer<T> const &other)
    {
        __release__();

        if (other.not_null()) {
            this->__obj__ = other.__obj__;
            this->__count_mutex__ = other.__count_mutex__;

            ASSERT(0 == ::pthread_mutex_lock(this->__count_mutex__));
            this->__obj__->__ref_increase__();
            ASSERT(0 == ::pthread_mutex_unlock(this->__count_mutex__));
        }

        return *this;
    }

    virtual ~SmartPointer<T>(void)
    {
        __release__();
    }

public:
    intptr_t operator ==(void *p) const
    {
        return p == __obj__;
    }
    intptr_t operator !=(void *p) const
    {
        return p != __obj__;
    }
    intptr_t operator ==(SmartPointer const &other) const
    {
        return other.__obj__ == this->__obj__;
    }
    intptr_t operator !=(SmartPointer const &other) const
    {
        return other.__obj__ != this->__obj__;
    }
    intptr_t is_null(void) const
    {
        return NULL == __obj__;
    }
    intptr_t not_null(void) const
    {
        return NULL != __obj__;
    }
    T *operator ->(void)
    {
        return __obj__;
    }
    T &operator *(void)
    {
        return *__obj__;
    }
    void release(void)
    {
        __release__();

        return;
    }

    void copy(SmartPointer<T> const &other)
    {
        __release__();
        if (other.not_null()) {
            __obj__ = new T(*static_cast<SmartPointer>(other));
            __count_mutex__ = __obj__->__count_mutex__;

            ASSERT(0 == ::pthread_mutex_lock(__count_mutex__));
            __obj__->__ref_increase__();
            ASSERT(0 == ::pthread_mutex_unlock(__count_mutex__));
        }

        return;
    }

private:
    void __release__(void)
    {
        intptr_t ref_count = 0;

        if (NULL == this->__obj__) {
            return;
        }

        ASSERT(0 == ::pthread_mutex_lock(this->__count_mutex__));
        __obj__->__ref_decrease__();
        ref_count = __obj__->__get_ref_count__();
        if (0 == ref_count) {
            delete __obj__;
        }
        __obj__ = NULL;
        ASSERT(0 == ::pthread_mutex_unlock(this->__count_mutex__));

        if (0 == ref_count) {
            ::pthread_mutex_destroy(this->__count_mutex__);
            free(this->__count_mutex__);
        }
        this->__count_mutex__ = NULL;

        return;
    }

private:
    T *__obj__;
    pthread_mutex_t *__count_mutex__; // todo: cas instead
};

template <typename T>
typename cotasia::SmartPointer<T> cotasia::SmartPointer<T>::null_pointer;
#endif // __COTASIA_SMART_POINTER_H__
